【X68000(Z)アセンブラ講座 第023回 DMA(リンクモード)によるCG画像高速描画(ソースコード編)】 2025/06/17   サンプルプログラムを動かす前に 256×256ピクセル8ビットカラー(256色)のBMP画像ファイルを用意して 'BM_TEST7.bmp'と言うファイル名で保存して下さい。 破線の内側を'DMA_L.s'と言うファイル名で保存して下さい。 ------------------------------------------------------------------------------------------------ ******************************************************************************** * * アプリ名 : DMA_L.x * * DMA(リンクアレイチェインモード)を使ってCG画像高速描画アプリ * * Ver1.00 * ******************************************************************************** include A:\XC\INCLUDE\DOSCALL.MAC include A:\XC\INCLUDE\IOCSCALL.MAC * システム領域のアドレス cg_palette equ $E82000 * CG用パレットデータの先頭アドレス dmaptr equ $e84080 * DMAレジスター2の先頭アドレス * 以下DMAレジスターアドレスの先頭からのオフセット(距離) csr equ 0 cer equ 1 spare1 equ 2 dcr equ 4 ocr equ 5 scr equ 6 ccr_ equ 7 spare2 equ 8 mtc equ 10 mar equ 12 space3 equ 16 dar equ 20 spare4 equ 24 btc equ 26 bar equ 28 spare5 equ 32 spare6 equ 36 niv equ 37 spare7 equ 38 eiv equ 39 spare8 equ 40 mfc equ 41 spare9 equ 42 spare10 equ 44 cpr equ 45 spare11 equ 46 spare12 equ 48 dfc_ equ 49 spare13 equ 50 spare14 equ 54 spare15 equ 56 bfc equ 57 spare16 equ 58 spare17 equ 62 gcr equ 63 .cpu 68000 * CPUのタイプ .data * '.data'以降のデータはデータセクションに配置される file00: dc.b 'BM_TEST7.bmp',0 * 読み込むBMPのファイル名 msg_return: dc.b 13,10,0 * 改行コード('13'+'10') & 終端コード('0') msg01: dc.b 'BMP File Name : ',0 msg02: dc.b 'File Open Error !',13,10,0 .even * '.even'以降の偶数アドレスにデータを置く fh: dc.w 0 dma_x: dc.l 0 dma_y: dc.l 0 dma_width: dc.l 0 dma_height dc.l 0 bmp_header_start: * bmp_header_endまでBMPファイルのヘッダーデータ領域 BMFH: * BITMAPFILEHEADER bmph: dc.b 0, 0 * 'B'と'M'ならばBMP形式画像 dc.l 0 dc.w 0 dc.w 0 dc.l 0 BMIH: * BITMAPINFOHEADER biSize: dc.l 0 biWidth: dc.w 0, 0 * 横ピクセル数 biHeight: dc.w 0, 0 * 縦ピクセル数 dc.w 0 biBitCount: dc.w 0 * カラーモード(4/8/16/24/32) dc.l 0 dc.l 0 dc.l 0 dc.l 0 biClrUsed: dc.w 0, 0 dc.l 0 bmp_header_end: * BMPファイルのヘッダー領域の終わり .bss * '.bss'以降データバッファ BMPal ds.b 1024 * パレットデータ(4*256byte) bmtemp: ds.b 65536 * ピクセルデータ読み込みバッファ(256*256byte) pic ds.b 131072 * VRAMにDMA転送して表示する画像データ(256*256*2byte) dma_array_table:ds.b 2560 * 転送情報テーブル (4 + 2 + 4) * 256 .text * '.text'以降のプログラムはテキストセクションに配置される start: * スタートアドレス * ユーザーモードからスーパーバイザーモードに移行する moveq.l #_B_SUPER,d0 * d0にIOCS(BIOS)機能番号を代入 movea.l #0,a1 * a1に0を代入 trap #15 * IOCSコール実行 * 画面モードの設定 moveq.l #_CRTMOD,d0 * 画面モードの設定 move.w #8,d1 * 画面モードの番号 : 16 = 768x512x4 / 8 = 512x512x8 trap #15 * 画面をクリアして表示をオンにする moveq.l #_G_CLR_ON,d0 * 画面をクリアして表示をオンにする trap #15 pea msg01 * 文字列データmsg01のアドレスをスタックに積む dc.w _PRINT * 文字列の表示 addq.l #4,sp * spの位置を元に戻す pea file00 * ファイル名の先頭アドレスをスタックに積む dc.w _PRINT addq.l #4,sp pea msg_return * 改行するために改行コードのアドレスをスタックに積む dc.w _PRINT addq.l #4,sp bsr load_bmp * BMPファイル読み込みルーチンの呼び出し bsr set_palette * CGパレット設定ルーチンの呼び出し * ファイルから読み込んだ8ビットの画像データをX68Kの16ビットピクセル幅に変換 bsr init_pic * DMA転送描画に使う配列データの準備 move.l #64,d0 * 描画開始X座標(0-256の範囲で指定可能) move.l #64,d1 * 描画開始Y座標(0-256の範囲で指定可能) move.l #256,d2 * 横描画ピクセル数 move.l #256,d3 * 縦描画ピクセル数 bsr set_dma_table loop: * DMAによる画像高速描画 bsr dma_setup bsr dma_start bsr dma_wait_complete * ESCキーのチェック moveq.l #_BITSNS,d0 moveq.l #0,d1 trap #15 and.b #%00000010,d0 tst.b d0 bne end bra loop end: moveq.l #_CRTMOD,d0 move.w #16,d1 trap #15 * ユーザーモードに戻る moveq.l #_B_SUPER,d0 move.l SP,a1 trap #15 * アプリ終了 dc.w _EXIT load_bmp: * BMPファイルのデータを読み込む * ファイルアクセス開始 move.w #0,-(sp) * アクセスモードを指定。0 = 読み込みモード/1 = 書き込みモード pea file00 * ファイル名の先頭アドレスをスタックに積む dc.w _OPEN * ファイルのオープン addq.l #6,sp * SPの位置を元に戻す tst.l d0 * もしd0がプラスなら、 bpl load_bmp_0 * ラベルload_bmp_0に飛ぶ。 pea msg02 * エラーメッセージ dc.w _PRINT addq.l #4,sp dc.w _EXIT * ソフトウェアの終了 load_bmp_0: move.w d0,fh * _OPENを実行した後にd0にファイルハンドルが入っているので * d0のファイル管理番号をfhに保存する * BMFH read move.l #14,-(sp) * 読み込みバイト数をスタックに積む pea BMFH * アドレスBMFHをスタックに積む move.w fh,-(sp) * ファイルハンドルをスタックに積む dc.w _READ * OSコール実行 : ファイルの読み込み add.l #10,sp * SPの位置を元に戻す load_bmp_1: * BMIH read move.l #40,-(sp) * 40byteのファイルヘッダー pea BMIH move.w fh,-(sp) dc.w _READ * ファイル読み込み lea 10(sp),sp * BMP パレットの読み込み move.l #1024,-(sp) * パレットデータのサイズをスタックに積む pea BMPal move.w fh,-(sp) dc.w _READ lea 10(sp),sp * BMP ピクセルデータの読み込み move.l #65536,-(sp) * ピクセルデータのサイズをスタックに積む pea bmtemp * bmtemp = 読み込んだピクセルデータを配置するアドレス move.w fh,-(sp) dc.w _READ lea 10(sp),sp * ファイルアクセス終了 move.w fh,-(sp) dc.w _CLOSE addq.l #2,sp rts * サブルーチンの最後に配置(呼出元にリターンし次の命令から実行再開) * RGBQUAD { Blue8, Green8, Red8, Reserved8 } = %RRRRRRRR_GGGGGGGG_BBBBBBBB_AAAAAAAA * palette { Green5, Red5, Blue5, Alpha1 } = %GGGGGRRR_RRBBBBB0 * Set CG Palette set_palette: movea.l #cg_palette,a0 * CG用パレットレジスターアドレス lea BMPal,a1 * パレットデータバッファアドレス moveq.l #0,d7 set_palette_1: move.b (a1),d0 * a1が示すアドレスからd0にバイトデータを読み込む * ↓32ビット色の青色成分8ビットのうち上位5ビットを抜き取り16ビット色の青色成分として使う lsr.w #2,d0 * 青色ビットデータの位置を16ビット色内の青色位置に右シフト and.w #%0000000000111110,d0 * 16ビット色の青色成分以外のビットを0にする move.b 1(a1),d1 * a1に1を足したアドレスからd1にバイトデータを読み込む * ↓32ビット色の緑色成分8ビットのうち上位5ビットを抜き取り16ビット色の緑色成分として使う lsl.w #8,d1 * 緑色ビットデータの位置を16ビット色内の緑色位置に左シフト and.w #%1111100000000000,d1 * 16ビット色の緑色成分以外のビットを0にする move.b 2(a1),d2 * a1に2を足したアドレスからd2にバイトデータを読み込む * ↓32ビット色の赤色成分8ビットのうち上位5ビットを抜き取り16ビット色の赤色成分として使う lsl.w #3,d2 * 赤色ビットデータの位置を16ビット色内の赤色位置に左シフト and.w #%0000011111000000,d2 * 16ビット色の赤色成分以外のビットを0にする * 青赤緑のそれぞれの色成分を論理和命令で一つの16ビットカラーに完成させる or.w d1,d0 or.w d2,d0 * 完成した色データをパレットメモリーに書き込んで更新する move.w d0,(a0)+ * 16ビットデータを書き込んだ後にa0に2を足す * 次の変換元色データを取り出す前にa1のアドレスを更新しておく addq.l #4,a1 addq.w #1,d7 * 色番号を次の番号に更新する cmp.w #256,d7 * 現在の色番号と256を比較する blt set_palette_1 * 現在の色番号が256未満ならアドレスset_palette_1に飛ぶ rts * 呼出元に戻る init_pic: lea bmtemp,a0 lea pic,a1 moveq.l #0,d7 init_pic_1: move.b (a0)+,d0 move.w d0,(a1)+ addq.l #1,d7 cmp.l #524288/4,d7 blt init_pic_1 rts set_dma_table: * in d0.l = 描画開始X座標 * in d1.l = 描画開始Y座標 * in d2.l = 横描画ピクセル数 * in d3.l = 縦描画ピクセル数 movem.l d0/d1/d7/a0/a1,-(sp) move.l d0,dma_x move.l d1,dma_y move.l d2,dma_width move.l d3,dma_height * 描画開始VRAMアドレスの計算 move.l #$C00000,a0 * VRAM先頭アドレス moveq.l #10,d7 lsl.l d7,d1 * d1.lの値を左に10ビットシフト( =d1.lに1024を掛け算する) add.l d0,d0 * d0.lの値を2倍にする add.l d0,d1 * d1.lにd0.lを足す add.l d1,a0 * a0.lにd1.lを足して描画開始VRAMアドレスの完成 * アレイモード用データの構築 lea dma_array_table,a1 move.w d3,d7 subq.w #1,d7 set_dma_table_1: move.l a0,(a1) * 描画先のアドレスを格納する add.l #512*2,a0 * 次のY座標に更新するために1024をa0.lに足す move.w d2,4(a1) * 横のピクセル数を格納する move.l a1,d0 * a1.lの値をテーブル計算用にd0.lへコピーする add.l #10,d0 * テーブルの中の次のリンク先を更新するために10を足す move.l d0,6(a1) * 次のリンク先をテーブルに書き込んで繋げる add.l #10,a1 * テーブルの中の参照先を次のピクセルラインに更新する dblt d7,set_dma_table_1 sub.l #10,a1 * テーブルの中の最後のエントリーに戻る move.l #0,6(a1) * 最後のエントリーの証として0を必ず置く movem.l (sp)+,d0/d1/d7/a0/a1 rts * DMA転送が終わるまで待つ dma_wait_complete: movem.l d0/a0,-(sp) movea.l #dmaptr,a0 dma_wait_complete_1: move.b (a0),d0 and.b #$90,d0 cmp.b #0,d0 beq dma_wait_complete_1 movem.l (sp)+,d0/a0 rts * DMA転送スタート dma_start: move.l a0,-(sp) movea.l #dmaptr,a0 or.b #$80,ccr_(a0) move.l (sp)+,a0 rts * DMA転送開始前の設定 dma_setup: movem.l a0/a6,-(sp) movea.l #dmaptr,a6 move.b #$ff,csr(a6) * フラグのクリアー move.b #$08,dcr(a6) * 16Bitポート move.b #$9d,ocr(a6) * 転送=ワード(16Bit)単位 / オートリクエスト最大速度 move.b #%0000_01_01,scr(a6) * 転送元も転送先もレジスタの値は増加 move.b #$00,ccr_(a6) * デフォルト move.b #$000000_11,cpr(a6) * チャンネルプライオリティ : もっとも低い move.b #$05,mfc(a6) * スーパーバイザーデータ move.b #$05,dfc_(a6) * スーパーバイザーデータ move.b #$05,bfc(a6) * スーパーバイザーデータ lea pic,a0 move.l a0,dar(a6) lea dma_array_table,a0 move.l a0,bar(a6) movem.l (sp)+,a0/a6 rts * [EOF] ------------------------------------------------------------------------------------------------ コマンドプロンプトから、 A>as DMA_L.s [Enter] A>lk DMA_L.o [Enter] A>DMA_L.x [Enter] のように入力すると DMAによって用意した画像ファイルが表示されます。 ESCキーで終了します。